Applied exercises
- This exercise relates to the College data set, which can be found in the file College.csv. It contains a number of variables for 777 different universities and colleges in the US. The variables are:
• Private : Public/private indicator
• Apps : Number of applications received
• Accept : Number of applicants accepted
• Enroll : Number of new students enrolled
• Top10perc : New students from top 10 % of high school class
• Top25perc : New students from top 25 % of high school class
• F.Undergrad : Number of full-time undergraduates
• P.Undergrad : Number of part-time undergraduates
• Outstate : Out-of-state tuition
• Room.Board : Room and board costs
• Books : Estimated book costs
• Personal : Estimated personal spending
• PhD : Percent of faculty with Ph.D.’s
• Terminal : Percent of faculty with terminal degree
• S.F.Ratio : Student/faculty ratio
• perc.alumni : Percent of alumni who donate
• Expend : Instructional expenditure per student
• Grad.Rate : Graduation rate
Before reading the data into R, it can be viewed in Excel or a text editor.
- Use the read.csv() function to read the data into R. Call the loaded data college. Make sure that you have the directory set to the correct location for the data.
library(ISLR)
head(College)
- Look at the data using the fix() function. You should notice that the first column is just the name of each university. We don’t really want R to treat this as data. However, it may be handy to have these names for later. Try the following commands:
In the ISLR package the version of College has the row names already assigned as the unviersity names.
- Use the summary() function to produce a numerical summary of the variables in the data set.
- Use the pairs() function to produce a scatterplot matrix of the first ten columns or variables of the data. Recall that you can reference the first ten columns of a matrix A using A[,1:10].
- Use the plot() function to produce side-by-side boxplots of Outstate versus Private.
- Create a new qualitative variable, called Elite, by binning the Top10perc variable. We are going to divide universities into two groups based on whether or not the proportion of students coming from the top 10% of their high school classes exceeds 50 %.
library(ggplot2)
lapply(College, summary)
$Private
No Yes
212 565
$Apps
Min. 1st Qu. Median Mean 3rd Qu. Max.
81 776 1558 3002 3624 48090
$Accept
Min. 1st Qu. Median Mean 3rd Qu. Max.
72 604 1110 2019 2424 26330
$Enroll
Min. 1st Qu. Median Mean 3rd Qu. Max.
35 242 434 780 902 6392
$Top10perc
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.00 15.00 23.00 27.56 35.00 96.00
$Top25perc
Min. 1st Qu. Median Mean 3rd Qu. Max.
9.0 41.0 54.0 55.8 69.0 100.0
$F.Undergrad
Min. 1st Qu. Median Mean 3rd Qu. Max.
139 992 1707 3700 4005 31640
$P.Undergrad
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.0 95.0 353.0 855.3 967.0 21840.0
$Outstate
Min. 1st Qu. Median Mean 3rd Qu. Max.
2340 7320 9990 10440 12920 21700
$Room.Board
Min. 1st Qu. Median Mean 3rd Qu. Max.
1780 3597 4200 4358 5050 8124
$Books
Min. 1st Qu. Median Mean 3rd Qu. Max.
96.0 470.0 500.0 549.4 600.0 2340.0
$Personal
Min. 1st Qu. Median Mean 3rd Qu. Max.
250 850 1200 1341 1700 6800
$PhD
Min. 1st Qu. Median Mean 3rd Qu. Max.
8.00 62.00 75.00 72.66 85.00 103.00
$Terminal
Min. 1st Qu. Median Mean 3rd Qu. Max.
24.0 71.0 82.0 79.7 92.0 100.0
$S.F.Ratio
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.50 11.50 13.60 14.09 16.50 39.80
$perc.alumni
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.00 13.00 21.00 22.74 31.00 64.00
$Expend
Min. 1st Qu. Median Mean 3rd Qu. Max.
3186 6751 8377 9660 10830 56230
$Grad.Rate
Min. 1st Qu. Median Mean 3rd Qu. Max.
10.00 53.00 65.00 65.46 78.00 118.00
$Elite
Length Class Mode
777 character character
pairs(College[1:10])

boxplot(College$Outstate ~ College$Private)

College$Elite <- ifelse(College$Top10perc > 50, "Yes", "No")
Use the summary() function to see how many elite universities there are. Now use the plot() function to produce side-by-side boxplots of Outstate versus Elite.
summary(College$Elite)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.0000 0.0000 0.1004 0.0000 1.0000
10% of colleges are ‘Elite’.
- Use the hist() function to produce some histograms with differing numbers of bins for a few of the quantitative variables. You may find the command par(mfrow=c(2,2)) useful: it will divide the print window into four regions so that four plots can be made simultaneously. Modifying the arguments to this function will divide the screen in other ways.
hist(College$Enroll)

hist(College$F.Undergrad)

hist(College$PhD)

hist(College$Accept/College$Apps) # Per every application, barely anyone accepts a student.

hist(College$Grad.Rate[College$Private == "Yes"])

hist(College$Grad.Rate[College$Private == "No"])

- Continue exploring the data, and provide a brief summary of what you discover.
To do.
- This exercise involves the Auto data set studied in the lab. Make sure that the missing values have been removed from the data.
- Which of the predictors are quantitative, and which are qualitative?
lapply(Auto[-ncol(Auto)], summary)
$mpg
Min. 1st Qu. Median Mean 3rd Qu. Max.
9.00 17.00 22.75 23.45 29.00 46.60
$cylinders
Min. 1st Qu. Median Mean 3rd Qu. Max.
3.000 4.000 4.000 5.472 8.000 8.000
$displacement
Min. 1st Qu. Median Mean 3rd Qu. Max.
68.0 105.0 151.0 194.4 275.8 455.0
$horsepower
Min. 1st Qu. Median Mean 3rd Qu. Max.
46.0 75.0 93.5 104.5 126.0 230.0
$weight
Min. 1st Qu. Median Mean 3rd Qu. Max.
1613 2225 2804 2978 3615 5140
$acceleration
Min. 1st Qu. Median Mean 3rd Qu. Max.
8.00 13.78 15.50 15.54 17.02 24.80
$year
Min. 1st Qu. Median Mean 3rd Qu. Max.
70.00 73.00 76.00 75.98 79.00 82.00
$origin
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 1.000 1.000 1.577 2.000 3.000
- What is the range of each quantitative predictor? You can answer this using the range() function.
lapply(Auto[c("mpg", "displacement", "horsepower", "weight", "acceleration", "year")], range)
$mpg
[1] 9.0 46.6
$displacement
[1] 68 455
$horsepower
[1] 46 230
$weight
[1] 1613 5140
$acceleration
[1] 8.0 24.8
$year
[1] 70 82
- What is the mean and standard deviation of each quantitative predictor?
lapply(Auto[c("mpg", "displacement", "horsepower", "weight", "acceleration", "year")], mean)
$mpg
[1] 23.44592
$displacement
[1] 194.412
$horsepower
[1] 104.4694
$weight
[1] 2977.584
$acceleration
[1] 15.54133
$year
[1] 75.97959
- Now remove the 10th through 85th observations. What is the range, mean, and standard deviation of each predictor in the subset of the data that remains?
basic <- function(x) {
summary <- c(mean = mean(x, na.rm = T), range = range(x, na.rm = T), sd = sd(x, na.rm = T))
summary
}
lapply(Auto[-(10:85), -ncol(Auto)], basic)
$mpg
mean range1 range2 sd
24.404430 11.000000 46.600000 7.867283
$cylinders
mean range1 range2 sd
5.373418 3.000000 8.000000 1.654179
$displacement
mean range1 range2 sd
187.24051 68.00000 455.00000 99.67837
$horsepower
mean range1 range2 sd
100.72152 46.00000 230.00000 35.70885
$weight
mean range1 range2 sd
2935.9715 1649.0000 4997.0000 811.3002
$acceleration
mean range1 range2 sd
15.726899 8.500000 24.800000 2.693721
$year
mean range1 range2 sd
77.145570 70.000000 82.000000 3.106217
$origin
mean range1 range2 sd
1.601266 1.000000 3.000000 0.819910
- Using the full data set, investigate the predictors graphically, using scatterplots or other tools of your choice. Create some plots highlighting the relationships among the predictors. Comment on your findings.
plot(Auto[1:ncol(Auto) - 1])

It’s interesting to find that mpg is negatively related to displacement, horsepower and weight in a similar way. In fact, the correlation are:
correlations <- c(first = cor(Auto$mpg, Auto$displacement), second = cor(Auto$mpg, Auto$horsepower), third = cor(Auto$mpg, Auto$weight))
correlations
first second third
-0.8051269 -0.7784268 -0.8322442
All within a 5 figure difference. and above -0.70. In contrast, the correlations between displacement, horsepower and weight are strong and positive.
correlations2 <- c(displa_horse = cor(Auto$displacement, Auto$horsepower), displace_weight = cor(Auto$displacement, Auto$weight), horsep_weight = cor(Auto$horsepower, Auto$weight))
correlations2
displa_horse displace_weight horsep_weight
0.8972570 0.9329944 0.8645377
plot(Auto$displacement, Auto$horsepower)

plot(Auto$displacement, Auto$weight)

plot(Auto$horsepower, Auto$weight)

- Suppose that we wish to predict gas mileage (mpg) on the basis of the other variables. Do your plots suggest that any of the other variables might be useful in predicting mpg? Justify your answer.
Yeah, just as we saw in the matrix scatterplot, mpg is highly correlated with several variables. Not only there’s a visual pattern, but the correlation coefficients are substantial.
- To begin, load in the Boston data set.
library(MASS)
head(Boston)
How many rows are in this data set? How many columns? What do the rows and columns represent?
dim(Boston)
[1] 506 14
The data has 506 rows and 14 columns. Each row represents housing values in suburbs from Boston. See help(Boston).
- Make some pairwise scatterplots of the predictors (columns) in this data set. Describe your findings.
plot(Boston)

Well, I find interesting that there’s some clear non-linear patterns such as in nox ~ dis as well as Istat ~ medv and rm ~ Istat.
- Are any of the predictors associated with per capita crime rate? If so, explain the relationship.
crim is correlated with age, div, lstat and medv. The relationships are not straightforward though.
for (i in c("age", "dis", "lstat", "medv")) {
plot(Boston[, i], Boston[,"crim"], xlab = paste(i))
}




As the proportion of owner-occupied units built prior to 1940 increases, crime rates increase. But note that there are threshold effects. At around 40% of age, crime rates start to increase and only at around 80% it becomes substantial. This relationship might not be that strong linearly, but once you account for non-linearities it might be significant.
With dis (distance to five Boston employment centres), crime rates are higher only when employment centers are close, but as it passes increases over 4, crime rates set at 0.
With lstat it’s similar as with age, crime rates increases only after some value, more or less around 15. It seems that crime rates are not linearly related to almost any of these variables. The same pattern can be found with medv.
- Do any of the suburbs of Boston appear to have particularly high crime rates? Tax rates? Pupil-teacher ratios? Comment on the range of each predictor.
library(car)
Boxplot(Boston$crim)
[1] 381 419 406 411 415 405 399 428 414 418

Above the graph we can see the outliers which have significantly higher crime rates than the overall distribution. 10 suburbs, so not a small bunch.
Boxplot(Boston$ptratio)
[1] 197 198 199 258 259 260 261 262 263 264

Boxplot(Boston$tax)

ptratio does have some outliers, but they’re not the same ones in crime rates. Surprisingly, tax doesn`t have any outliers, and the distribution is pretty smooth.
for (i in c("crim", "ptratio", "tax")) {
print(range(Boston[, i]))
}
[1] 0.00632 88.97620
[1] 12.6 22.0
[1] 187 711
The range of crime rates can be as high as 88% and as low as 0%, quite some diversity between suburbs. Student-teacher ratio is much smaller, with a maximum of 22 students and a minimum of 13. Tax ranges from 187 to 711.
- How many of the suburbs in this data set bound the Charles river?
table(Boston$chas)
0 1
471 35
35 suburs.
- What is the median pupil-teacher ratio among the towns in this data set?
median(Boston$ptratio)
[1] 19.05
19 pupils per teacher.
- Which suburb of Boston has lowest median value of owner- occupied homes? What are the values of the other predictors for that suburb, and how do those values compare to the overall ranges for those predictors? Comment on your findings.
Boston[Boston$medv == min(Boston$medv), ]
Actually, both suburb 399 and 406 have the same lowest median value, which is 5.
First, both suburbs have virtually the same values for all predictors except for the crim, lstat and black variables. The crim variable is quite different with the second suburb having a really high crime rate compared to the maximum crime rate of 88% which is only happening in one suburb. The proportion of residential land zoned for lots over 25k sq.ft is 0 for both suburs, and the maximum is 100%. So no land zoned for lots in those suburbs. The indus variable is reasonably high with 18% while the minimum is 0% and the maximum is 27%. Both suburbs are not close to the Charles River and have high nitrogen oxide concentration at about 69% with the maximum being 87% and the minimum 38%.
Their number of rooms per dwelling is pretty average at 5.4/5.6 while the min is 3 and the max 9. Both suburbs are completely occupied by units built prior to 1940 and are reasonably close to five Boston employment centres (1.4 when the minimum is 1 and the highest 12.) Also both are at the maximum index of accesibility to radial highways, and that’s reasonably high as the minimum is 1 and they’re at 24.
The pupil-teacher ratio is 20.2 and the minimum is 12. As expected, both suburbs are highly populated by blacks, with one of the suburbs actually being the maximum number in the distribution. The lower status of the population is not unusually high, with the maximum and minimum being 37.9 and 1.73 and both suburbs are 30.5 and 22.9.
- In this data set, how many of the suburbs average more than seven rooms per dwelling? More than eight rooms per dwelling? Comment on the suburbs that average more than eight rooms per dwelling.
table(Boston$rm > 7)
FALSE TRUE
442 64
table(Boston$rm > 8)
FALSE TRUE
493 13
Only 64 suburbs average above seven rooms, and only 13 average above eight rooms.
There are some outliers in these suburbs but they all have high age values, so a lot of owner occupied units prior to 1940. Also, all have high black density within their towns. All are far from the Charles River except suburb 164, and the proportion of residential land zone for lots over 25,000 sq.ft is zero with the exception of suburb 205.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBBcHBsaWVkIGV4ZXJjaXNlcwoKOC4gVGhpcyBleGVyY2lzZSByZWxhdGVzIHRvIHRoZSBDb2xsZWdlIGRhdGEgc2V0LCB3aGljaCBjYW4gYmUgZm91bmQgaW4gdGhlIGZpbGUgQ29sbGVnZS5jc3YuIEl0IGNvbnRhaW5zIGEgbnVtYmVyIG9mIHZhcmlhYmxlcyBmb3IgNzc3IGRpZmZlcmVudCB1bml2ZXJzaXRpZXMgYW5kIGNvbGxlZ2VzIGluIHRoZSBVUy4gVGhlIHZhcmlhYmxlcyBhcmU6CgrigKIgUHJpdmF0ZSA6IFB1YmxpYy9wcml2YXRlIGluZGljYXRvciAgPGJyPgrigKIgQXBwcyA6IE51bWJlciBvZiBhcHBsaWNhdGlvbnMgcmVjZWl2ZWQgPGJyPgrigKIgQWNjZXB0IDogTnVtYmVyIG9mIGFwcGxpY2FudHMgYWNjZXB0ZWQgPGJyPgrigKIgRW5yb2xsIDogTnVtYmVyIG9mIG5ldyBzdHVkZW50cyBlbnJvbGxlZCA8YnI+CuKAoiBUb3AxMHBlcmMgOiBOZXcgc3R1ZGVudHMgZnJvbSB0b3AgMTAgJSBvZiBoaWdoIHNjaG9vbCBjbGFzcyA8YnI+CuKAoiBUb3AyNXBlcmMgOiBOZXcgc3R1ZGVudHMgZnJvbSB0b3AgMjUgJSBvZiBoaWdoIHNjaG9vbCBjbGFzcyA8YnI+CuKAoiBGLlVuZGVyZ3JhZCA6IE51bWJlciBvZiBmdWxsLXRpbWUgdW5kZXJncmFkdWF0ZXM8YnI+CuKAoiBQLlVuZGVyZ3JhZCA6IE51bWJlciBvZiBwYXJ0LXRpbWUgdW5kZXJncmFkdWF0ZXM8YnI+CuKAoiBPdXRzdGF0ZSA6IE91dC1vZi1zdGF0ZSB0dWl0aW9uPGJyPgrigKIgUm9vbS5Cb2FyZCA6IFJvb20gYW5kIGJvYXJkIGNvc3RzPGJyPgrigKIgQm9va3MgOiBFc3RpbWF0ZWQgYm9vayBjb3N0czxicj4K4oCiIFBlcnNvbmFsIDogRXN0aW1hdGVkIHBlcnNvbmFsIHNwZW5kaW5nPGJyPgrigKIgUGhEIDogUGVyY2VudCBvZiBmYWN1bHR5IHdpdGggUGguRC7igJlzPGJyPgrigKIgVGVybWluYWwgOiBQZXJjZW50IG9mIGZhY3VsdHkgd2l0aCB0ZXJtaW5hbCBkZWdyZWU8YnI+CuKAoiBTLkYuUmF0aW8gOiBTdHVkZW50L2ZhY3VsdHkgcmF0aW88YnI+CuKAoiBwZXJjLmFsdW1uaSA6IFBlcmNlbnQgb2YgYWx1bW5pIHdobyBkb25hdGU8YnI+CuKAoiBFeHBlbmQgOiBJbnN0cnVjdGlvbmFsIGV4cGVuZGl0dXJlIHBlciBzdHVkZW50PGJyPgrigKIgR3JhZC5SYXRlIDogR3JhZHVhdGlvbiByYXRlPGJyPgoKQmVmb3JlIHJlYWRpbmcgdGhlIGRhdGEgaW50byBSLCBpdCBjYW4gYmUgdmlld2VkIGluIEV4Y2VsIG9yIGEgdGV4dCBlZGl0b3IuCgooYSkgVXNlIHRoZSByZWFkLmNzdigpIGZ1bmN0aW9uIHRvIHJlYWQgdGhlIGRhdGEgaW50byBSLiBDYWxsIHRoZSBsb2FkZWQgZGF0YSBjb2xsZWdlLiBNYWtlIHN1cmUgdGhhdCB5b3UgaGF2ZSB0aGUgZGlyZWN0b3J5IHNldCB0byB0aGUgY29ycmVjdCBsb2NhdGlvbiBmb3IgdGhlIGRhdGEuCmBgYHtyfQpsaWJyYXJ5KElTTFIpCmhlYWQoQ29sbGVnZSkKYGBgCgooYikgTG9vayBhdCB0aGUgZGF0YSB1c2luZyB0aGUgZml4KCkgZnVuY3Rpb24uIFlvdSBzaG91bGQgbm90aWNlIHRoYXQgdGhlIGZpcnN0IGNvbHVtbiBpcyBqdXN0IHRoZSBuYW1lIG9mIGVhY2ggdW5pdmVyc2l0eS4gV2UgZG9u4oCZdCByZWFsbHkgd2FudCBSIHRvIHRyZWF0IHRoaXMgYXMgZGF0YS4gSG93ZXZlciwgaXQgbWF5IGJlIGhhbmR5IHRvIGhhdmUgdGhlc2UgbmFtZXMgZm9yIGxhdGVyLiBUcnkgdGhlIGZvbGxvd2luZyBjb21tYW5kczoKCkluIHRoZSBgSVNMUmAgcGFja2FnZSB0aGUgdmVyc2lvbiBvZiBgQ29sbGVnZWAgaGFzIHRoZSByb3cgbmFtZXMgYWxyZWFkeSBhc3NpZ25lZCBhcyB0aGUgdW52aWVyc2l0eSBuYW1lcy4KCihjKQppLiBVc2UgdGhlIHN1bW1hcnkoKSBmdW5jdGlvbiB0byBwcm9kdWNlIGEgbnVtZXJpY2FsIHN1bW1hcnkgb2YgdGhlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQuCmlpLiBVc2UgdGhlIHBhaXJzKCkgZnVuY3Rpb24gdG8gcHJvZHVjZSBhIHNjYXR0ZXJwbG90IG1hdHJpeCBvZiB0aGUgZmlyc3QgdGVuIGNvbHVtbnMgb3IgdmFyaWFibGVzIG9mIHRoZSBkYXRhLiBSZWNhbGwgdGhhdCB5b3UgY2FuIHJlZmVyZW5jZSB0aGUgZmlyc3QgdGVuIGNvbHVtbnMgb2YgYSBtYXRyaXggQSB1c2luZyBBWywxOjEwXS4KaWlpLiBVc2UgdGhlIHBsb3QoKSBmdW5jdGlvbiB0byBwcm9kdWNlIHNpZGUtYnktc2lkZSBib3hwbG90cyBvZiBPdXRzdGF0ZSB2ZXJzdXMgUHJpdmF0ZS4KaXYuIENyZWF0ZSBhIG5ldyBxdWFsaXRhdGl2ZSB2YXJpYWJsZSwgY2FsbGVkIEVsaXRlLCBieSBiaW5uaW5nIHRoZSBUb3AxMHBlcmMgdmFyaWFibGUuIFdlIGFyZSBnb2luZyB0byBkaXZpZGUgdW5pdmVyc2l0aWVzIGludG8gdHdvIGdyb3VwcyBiYXNlZCBvbiB3aGV0aGVyIG9yIG5vdCB0aGUgcHJvcG9ydGlvbiBvZiBzdHVkZW50cyBjb21pbmcgZnJvbSB0aGUgdG9wIDEwJSBvZiB0aGVpciBoaWdoIHNjaG9vbCBjbGFzc2VzIGV4Y2VlZHMgNTAgJS4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxhcHBseShDb2xsZWdlLCBzdW1tYXJ5KQoKcGFpcnMoQ29sbGVnZVsxOjEwXSkKCmJveHBsb3QoQ29sbGVnZSRPdXRzdGF0ZSB+IENvbGxlZ2UkUHJpdmF0ZSkKCkNvbGxlZ2UkRWxpdGUgPC0gaWZlbHNlKENvbGxlZ2UkVG9wMTBwZXJjID4gNTAsIDEsIDApCmBgYAoKVXNlIHRoZSBzdW1tYXJ5KCkgZnVuY3Rpb24gdG8gc2VlIGhvdyBtYW55IGVsaXRlIHVuaXZlcnNpdGllcyB0aGVyZSBhcmUuIE5vdyB1c2UgdGhlIHBsb3QoKSBmdW5jdGlvbiB0byBwcm9kdWNlIHNpZGUtYnktc2lkZSBib3hwbG90cyBvZiBPdXRzdGF0ZSB2ZXJzdXMgRWxpdGUuCgpgYGB7cn0Kc3VtbWFyeShDb2xsZWdlJEVsaXRlKQoKYm94cGxvdChDb2xsZWdlJE91dHN0YXRlIH4gQ29sbGVnZSRFbGl0ZSkKYGBgCjEwJSBvZiBjb2xsZWdlcyBhcmUgJ0VsaXRlJy4KCnYuIFVzZSB0aGUgaGlzdCgpIGZ1bmN0aW9uIHRvIHByb2R1Y2Ugc29tZSBoaXN0b2dyYW1zIHdpdGggZGlmZmVyaW5nIG51bWJlcnMgb2YgYmlucyBmb3IgYSBmZXcgb2YgdGhlIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMuIFlvdSBtYXkgZmluZCB0aGUgY29tbWFuZCBwYXIobWZyb3c9YygyLDIpKSB1c2VmdWw6IGl0IHdpbGwgZGl2aWRlIHRoZSBwcmludCB3aW5kb3cgaW50byBmb3VyIHJlZ2lvbnMgc28gdGhhdCBmb3VyIHBsb3RzIGNhbiBiZSBtYWRlIHNpbXVsdGFuZW91c2x5LiBNb2RpZnlpbmcgdGhlIGFyZ3VtZW50cyB0byB0aGlzIGZ1bmN0aW9uIHdpbGwgZGl2aWRlIHRoZSBzY3JlZW4gaW4gb3RoZXIgd2F5cy4KCmBgYHtyfQpoaXN0KENvbGxlZ2UkRW5yb2xsKQpoaXN0KENvbGxlZ2UkRi5VbmRlcmdyYWQpCmhpc3QoQ29sbGVnZSRQaEQpCgpoaXN0KENvbGxlZ2UkQWNjZXB0L0NvbGxlZ2UkQXBwcykgIyBQZXIgZXZlcnkgYXBwbGljYXRpb24sIGJhcmVseSBhbnlvbmUgYWNjZXB0cyBhIHN0dWRlbnQuCgpoaXN0KENvbGxlZ2UkR3JhZC5SYXRlW0NvbGxlZ2UkUHJpdmF0ZSA9PSAxXSkKaGlzdChDb2xsZWdlJEdyYWQuUmF0ZVtDb2xsZWdlJFByaXZhdGUgPT0gMF0pCmBgYAp2aS4gQ29udGludWUgZXhwbG9yaW5nIHRoZSBkYXRhLCBhbmQgcHJvdmlkZSBhIGJyaWVmIHN1bW1hcnkgb2Ygd2hhdCB5b3UgZGlzY292ZXIuIDxicj4KVG8gZG8uCgo5LiBUaGlzIGV4ZXJjaXNlIGludm9sdmVzIHRoZSBBdXRvIGRhdGEgc2V0IHN0dWRpZWQgaW4gdGhlIGxhYi4gTWFrZSBzdXJlIHRoYXQgdGhlIG1pc3NpbmcgdmFsdWVzIGhhdmUgYmVlbiByZW1vdmVkIGZyb20gdGhlIGRhdGEuCmBgYHtyfQpoZWFkKEF1dG8pCmBgYAoKKGEpIFdoaWNoIG9mIHRoZSBwcmVkaWN0b3JzIGFyZSBxdWFudGl0YXRpdmUsIGFuZCB3aGljaCBhcmUgcXVhbGl0YXRpdmU/CmBgYHtyfQpsYXBwbHkoQXV0b1stbmNvbChBdXRvKV0sIHN1bW1hcnkpCiMgbXBnIC0gcXVhbnQKIyBjeWxpbmRlcnMgLSBxdWFsaQojIGRpc3BsYWNlbWVudCAtIHF1YW50aQojIGhvcnNlcG93ZXIgLSBxdWFudGkKIyB3ZWlnaHQgLSBxdWFudGkKIyBhY2NlbGVyYXRpb24gLSBxdWFudGkKIyB5ZWFyIC0gcXVhbnRpCiMgb3JpZ2luIC0gcXVhbGl0CiMgbmFtZSAtIHF1YWxpIC0gT01JVFRFRCBiZWNhdXNlIG9mIGxvbmcgb3V0cHV0CmBgYAoKKGIpIFdoYXQgaXMgdGhlIHJhbmdlIG9mIGVhY2ggcXVhbnRpdGF0aXZlIHByZWRpY3Rvcj8gWW91IGNhbiBhbnN3ZXIgdGhpcyB1c2luZyB0aGUgcmFuZ2UoKSBmdW5jdGlvbi4KCmBgYHtyfQpsYXBwbHkoQXV0b1tjKCJtcGciLCAiZGlzcGxhY2VtZW50IiwgImhvcnNlcG93ZXIiLCAid2VpZ2h0IiwgImFjY2VsZXJhdGlvbiIsICJ5ZWFyIildLCByYW5nZSkKYGBgCgooYykgV2hhdCBpcyB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGVhY2ggcXVhbnRpdGF0aXZlIHByZWRpY3Rvcj8KYGBge3J9CmxhcHBseShBdXRvW2MoIm1wZyIsICJkaXNwbGFjZW1lbnQiLCAiaG9yc2Vwb3dlciIsICJ3ZWlnaHQiLCAiYWNjZWxlcmF0aW9uIiwgInllYXIiKV0sIG1lYW4pCmBgYAoKKGQpIE5vdyByZW1vdmUgdGhlIDEwdGggdGhyb3VnaCA4NXRoIG9ic2VydmF0aW9ucy4gV2hhdCBpcyB0aGUgcmFuZ2UsIG1lYW4sIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgZWFjaCBwcmVkaWN0b3IgaW4gdGhlIHN1YnNldCBvZiB0aGUgZGF0YSB0aGF0IHJlbWFpbnM/CmBgYHtyfQpiYXNpYyA8LSBmdW5jdGlvbih4KSB7CiAgc3VtbWFyeSA8LSBjKG1lYW4gPSBtZWFuKHgsIG5hLnJtID0gVCksIHJhbmdlID0gcmFuZ2UoeCwgbmEucm0gPSBUKSwgc2QgPSBzZCh4LCBuYS5ybSA9IFQpKQogIHN1bW1hcnkKfQoKbGFwcGx5KEF1dG9bLSgxMDo4NSksIC1uY29sKEF1dG8pXSwgYmFzaWMpCmBgYAoKKGUpIFVzaW5nIHRoZSBmdWxsIGRhdGEgc2V0LCBpbnZlc3RpZ2F0ZSB0aGUgcHJlZGljdG9ycyBncmFwaGljYWxseSwgdXNpbmcgc2NhdHRlcnBsb3RzIG9yIG90aGVyIHRvb2xzIG9mIHlvdXIgY2hvaWNlLiBDcmVhdGUgc29tZSBwbG90cyBoaWdobGlnaHRpbmcgdGhlIHJlbGF0aW9uc2hpcHMgYW1vbmcgdGhlIHByZWRpY3RvcnMuIENvbW1lbnQgb24geW91ciBmaW5kaW5ncy4KYGBge3J9CnBsb3QoQXV0b1sxOm5jb2woQXV0bykgLSAxXSkKYGBgCkl0J3MgaW50ZXJlc3RpbmcgdG8gZmluZCB0aGF0IG1wZyBpcyBuZWdhdGl2ZWx5IHJlbGF0ZWQgdG8gZGlzcGxhY2VtZW50LCBob3JzZXBvd2VyIGFuZCB3ZWlnaHQgaW4gYSBzaW1pbGFyIHdheS4gSW4gZmFjdCwgdGhlIGNvcnJlbGF0aW9uIGFyZToKYGBge3J9CmNvcnJlbGF0aW9ucyA8LSBjKGZpcnN0ID0gY29yKEF1dG8kbXBnLCBBdXRvJGRpc3BsYWNlbWVudCksIHNlY29uZCA9IGNvcihBdXRvJG1wZywgQXV0byRob3JzZXBvd2VyKSwgdGhpcmQgPSBjb3IoQXV0byRtcGcsIEF1dG8kd2VpZ2h0KSkKY29ycmVsYXRpb25zCmBgYApBbGwgd2l0aGluIGEgNSBmaWd1cmUgZGlmZmVyZW5jZS4gYW5kIGFib3ZlIC0wLjcwLiBJbiBjb250cmFzdCwgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGRpc3BsYWNlbWVudCwgaG9yc2Vwb3dlciBhbmQgd2VpZ2h0IGFyZSBzdHJvbmcgYW5kIHBvc2l0aXZlLgoKYGBge3J9CmNvcnJlbGF0aW9uczIgPC0gYyhkaXNwbGFfaG9yc2UgPSBjb3IoQXV0byRkaXNwbGFjZW1lbnQsIEF1dG8kaG9yc2Vwb3dlciksIGRpc3BsYWNlX3dlaWdodCA9IGNvcihBdXRvJGRpc3BsYWNlbWVudCwgQXV0byR3ZWlnaHQpLCBob3JzZXBfd2VpZ2h0ID0gY29yKEF1dG8kaG9yc2Vwb3dlciwgQXV0byR3ZWlnaHQpKQoKY29ycmVsYXRpb25zMgpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0yfQpwbG90KEF1dG8kZGlzcGxhY2VtZW50LCBBdXRvJGhvcnNlcG93ZXIpCnBsb3QoQXV0byRkaXNwbGFjZW1lbnQsIEF1dG8kd2VpZ2h0KQpwbG90KEF1dG8kaG9yc2Vwb3dlciwgQXV0byR3ZWlnaHQpCmBgYAoKKGYpIFN1cHBvc2UgdGhhdCB3ZSB3aXNoIHRvIHByZWRpY3QgZ2FzIG1pbGVhZ2UgKG1wZykgb24gdGhlIGJhc2lzIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMuIERvIHlvdXIgcGxvdHMgc3VnZ2VzdCB0aGF0IGFueSBvZiB0aGUgb3RoZXIgdmFyaWFibGVzIG1pZ2h0IGJlIHVzZWZ1bCBpbiBwcmVkaWN0aW5nIG1wZz8gSnVzdGlmeSB5b3VyIGFuc3dlci4KClllYWgsIGp1c3QgYXMgd2Ugc2F3IGluIHRoZSBtYXRyaXggc2NhdHRlcnBsb3QsIG1wZyBpcyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIHNldmVyYWwgdmFyaWFibGVzLiBOb3Qgb25seSB0aGVyZSdzIGEgdmlzdWFsIHBhdHRlcm4sIGJ1dCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGFyZSBzdWJzdGFudGlhbC4KCjEwLiAKKGEpIFRvIGJlZ2luLCBsb2FkIGluIHRoZSBCb3N0b24gZGF0YSBzZXQuCmBgYHtyfQpsaWJyYXJ5KE1BU1MpCmhlYWQoQm9zdG9uKQpgYGAKCkhvdyBtYW55IHJvd3MgYXJlIGluIHRoaXMgZGF0YSBzZXQ/IEhvdyBtYW55IGNvbHVtbnM/IFdoYXQgZG8gdGhlIHJvd3MgYW5kIGNvbHVtbnMgcmVwcmVzZW50PwoKYGBge3J9CmRpbShCb3N0b24pCmBgYApUaGUgZGF0YSBoYXMgNTA2IHJvd3MgYW5kIDE0IGNvbHVtbnMuIEVhY2ggcm93IHJlcHJlc2VudHMgaG91c2luZyB2YWx1ZXMgaW4gc3VidXJicyBmcm9tIEJvc3Rvbi4gU2VlIGBoZWxwKEJvc3RvbilgLgoKKGIpIE1ha2Ugc29tZSBwYWlyd2lzZSBzY2F0dGVycGxvdHMgb2YgdGhlIHByZWRpY3RvcnMgKGNvbHVtbnMpIGluIHRoaXMgZGF0YSBzZXQuIERlc2NyaWJlIHlvdXIgZmluZGluZ3MuCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD03fQpwbG90KEJvc3RvbikKYGBgCldlbGwsIEkgZmluZCBpbnRlcmVzdGluZyB0aGF0IHRoZXJlJ3Mgc29tZSBjbGVhciBub24tbGluZWFyIHBhdHRlcm5zIHN1Y2ggYXMgaW4gYG5veCB+IGRpc2AgYXMgd2VsbCBhcyBgSXN0YXQgfiBtZWR2YCBhbmQgYHJtIH4gSXN0YXRgLgoKKGMpIEFyZSBhbnkgb2YgdGhlIHByZWRpY3RvcnMgYXNzb2NpYXRlZCB3aXRoIHBlciBjYXBpdGEgY3JpbWUgcmF0ZT8gSWYgc28sIGV4cGxhaW4gdGhlIHJlbGF0aW9uc2hpcC4KCmBjcmltYCBpcyBjb3JyZWxhdGVkIHdpdGggYGFnZWAsIGBkaXZgLCBgbHN0YXRgIGFuZCBgbWVkdmAuIFRoZSByZWxhdGlvbnNoaXBzIGFyZSBub3Qgc3RyYWlnaHRmb3J3YXJkIHRob3VnaC4KCmBgYHtyLCBmaWcud2lkdGg9Mn0KZm9yIChpIGluIGMoImFnZSIsICJkaXMiLCAibHN0YXQiLCAibWVkdiIpKSB7CnBsb3QoQm9zdG9uWywgaV0sIEJvc3RvblssImNyaW0iXSwgeGxhYiA9IHBhc3RlKGkpKQp9CmBgYApBcyB0aGUgcHJvcG9ydGlvbiBvZiBvd25lci1vY2N1cGllZCB1bml0cyBidWlsdCBwcmlvciB0byAxOTQwIGluY3JlYXNlcywgY3JpbWUgcmF0ZXMgaW5jcmVhc2UuIEJ1dCBub3RlIHRoYXQgdGhlcmUgYXJlIHRocmVzaG9sZCBlZmZlY3RzLiBBdCBhcm91bmQgNDAlIG9mIGFnZSwgY3JpbWUgcmF0ZXMgc3RhcnQgdG8gaW5jcmVhc2UgYW5kIG9ubHkgYXQgYXJvdW5kIDgwJSBpdCBiZWNvbWVzIHN1YnN0YW50aWFsLiBUaGlzIHJlbGF0aW9uc2hpcCBtaWdodCBub3QgYmUgdGhhdCBzdHJvbmcgbGluZWFybHksIGJ1dCBvbmNlIHlvdSBhY2NvdW50IGZvciBub24tbGluZWFyaXRpZXMgaXQgbWlnaHQgYmUgc2lnbmlmaWNhbnQuCgpXaXRoIGRpcyAoZGlzdGFuY2UgdG8gZml2ZSBCb3N0b24gZW1wbG95bWVudCBjZW50cmVzKSwgY3JpbWUgcmF0ZXMgYXJlIGhpZ2hlciBvbmx5IHdoZW4gZW1wbG95bWVudCBjZW50ZXJzIGFyZSBjbG9zZSwgYnV0IGFzIGl0IHBhc3NlcyBpbmNyZWFzZXMgb3ZlciA0LCBjcmltZSByYXRlcyBzZXQgYXQgMC4KCldpdGggYGxzdGF0YCBpdCdzIHNpbWlsYXIgYXMgd2l0aCBgYWdlYCwgY3JpbWUgcmF0ZXMgaW5jcmVhc2VzIG9ubHkgYWZ0ZXIgc29tZSB2YWx1ZSwgbW9yZSBvciBsZXNzIGFyb3VuZCAxNS4gSXQgc2VlbXMgdGhhdCBjcmltZSByYXRlcyBhcmUgbm90IGxpbmVhcmx5IHJlbGF0ZWQgdG8gYWxtb3N0IGFueSBvZiB0aGVzZSB2YXJpYWJsZXMuIFRoZSBzYW1lIHBhdHRlcm4gY2FuIGJlIGZvdW5kIHdpdGggYG1lZHZgLgoKKGQpIERvIGFueSBvZiB0aGUgc3VidXJicyBvZiBCb3N0b24gYXBwZWFyIHRvIGhhdmUgcGFydGljdWxhcmx5IGhpZ2ggY3JpbWUgcmF0ZXM/IFRheCByYXRlcz8gUHVwaWwtdGVhY2hlciByYXRpb3M/IENvbW1lbnQgb24gdGhlIHJhbmdlIG9mIGVhY2ggcHJlZGljdG9yLgpgYGB7cn0KbGlicmFyeShjYXIpCkJveHBsb3QoQm9zdG9uJGNyaW0pCmBgYApBYm92ZSB0aGUgZ3JhcGggd2UgY2FuIHNlZSB0aGUgb3V0bGllcnMgd2hpY2ggaGF2ZSBzaWduaWZpY2FudGx5IGhpZ2hlciBjcmltZSByYXRlcyB0aGFuIHRoZSBvdmVyYWxsIGRpc3RyaWJ1dGlvbi4gMTAgc3VidXJicywgc28gbm90IGEgc21hbGwgYnVuY2guCmBgYHtyfQpCb3hwbG90KEJvc3RvbiRwdHJhdGlvKQpCb3hwbG90KEJvc3RvbiR0YXgpCmBgYApgcHRyYXRpb2AgZG9lcyBoYXZlIHNvbWUgb3V0bGllcnMsIGJ1dCB0aGV5J3JlIG5vdCB0aGUgc2FtZSBvbmVzIGluIGNyaW1lIHJhdGVzLiBTdXJwcmlzaW5nbHksIGB0YXhgIGRvZXNuYHQgaGF2ZSBhbnkgb3V0bGllcnMsIGFuZCB0aGUgZGlzdHJpYnV0aW9uIGlzIHByZXR0eSBzbW9vdGguCgpgYGB7cn0KCmZvciAoaSBpbiBjKCJjcmltIiwgInB0cmF0aW8iLCAidGF4IikpIHsKICBwcmludChyYW5nZShCb3N0b25bLCBpXSkpCn0KYGBgClRoZSByYW5nZSBvZiBjcmltZSByYXRlcyBjYW4gYmUgYXMgaGlnaCBhcyA4OCUgYW5kIGFzIGxvdyBhcyAwJSwgcXVpdGUgc29tZSBkaXZlcnNpdHkgYmV0d2VlbiBzdWJ1cmJzLiBTdHVkZW50LXRlYWNoZXIgcmF0aW8gaXMgbXVjaCBzbWFsbGVyLCB3aXRoIGEgbWF4aW11bSBvZiAyMiBzdHVkZW50cyBhbmQgYSBtaW5pbXVtIG9mIDEzLiBUYXggcmFuZ2VzIGZyb20gMTg3IHRvIDcxMS4KCihlKSBIb3cgbWFueSBvZiB0aGUgc3VidXJicyBpbiB0aGlzIGRhdGEgc2V0IGJvdW5kIHRoZSBDaGFybGVzIHJpdmVyPwoKYGBge3J9CnRhYmxlKEJvc3RvbiRjaGFzKQpgYGAKMzUgc3VidXJzLgoKKGYpIFdoYXQgaXMgdGhlIG1lZGlhbiBwdXBpbC10ZWFjaGVyIHJhdGlvIGFtb25nIHRoZSB0b3ducyBpbiB0aGlzIGRhdGEgc2V0PwpgYGB7cn0KbWVkaWFuKEJvc3RvbiRwdHJhdGlvKQpgYGAKMTkgcHVwaWxzIHBlciB0ZWFjaGVyLgoKKGcpIFdoaWNoIHN1YnVyYiBvZiBCb3N0b24gaGFzIGxvd2VzdCBtZWRpYW4gdmFsdWUgb2Ygb3duZXItIG9jY3VwaWVkIGhvbWVzPyBXaGF0IGFyZSB0aGUgdmFsdWVzIG9mIHRoZSBvdGhlciBwcmVkaWN0b3JzIGZvciB0aGF0IHN1YnVyYiwgYW5kIGhvdyBkbyB0aG9zZSB2YWx1ZXMgY29tcGFyZSB0byB0aGUgb3ZlcmFsbCByYW5nZXMgZm9yIHRob3NlIHByZWRpY3RvcnM/IENvbW1lbnQgb24geW91ciBmaW5kaW5ncy4KCmBgYHtyfQpCb3N0b25bQm9zdG9uJG1lZHYgPT0gbWluKEJvc3RvbiRtZWR2KSwgXQpgYGAKQWN0dWFsbHksIGJvdGggc3VidXJiIDM5OSBhbmQgNDA2IGhhdmUgdGhlIHNhbWUgbG93ZXN0IG1lZGlhbiB2YWx1ZSwgd2hpY2ggaXMgNS4KCkZpcnN0LCBib3RoIHN1YnVyYnMgaGF2ZSB2aXJ0dWFsbHkgdGhlIHNhbWUgdmFsdWVzIGZvciBhbGwgcHJlZGljdG9ycyBleGNlcHQgZm9yIHRoZSBgY3JpbWAsIGBsc3RhdGAgYW5kIGBibGFja2AgdmFyaWFibGVzLgpUaGUgYGNyaW1gIHZhcmlhYmxlIGlzIHF1aXRlIGRpZmZlcmVudCB3aXRoIHRoZSBzZWNvbmQgc3VidXJiIGhhdmluZyBhIHJlYWxseSBoaWdoIGNyaW1lIHJhdGUgY29tcGFyZWQgdG8gdGhlIG1heGltdW0gY3JpbWUgcmF0ZSBvZiA4OCUgd2hpY2ggaXMgb25seSBoYXBwZW5pbmcgaW4gb25lIHN1YnVyYi4gVGhlIHByb3BvcnRpb24gb2YgcmVzaWRlbnRpYWwgbGFuZCB6b25lZCBmb3IgbG90cyBvdmVyIDI1ayBzcS5mdCBpcyAwIGZvciBib3RoIHN1YnVycywgYW5kIHRoZSBtYXhpbXVtIGlzIDEwMCUuIFNvIG5vIGxhbmQgem9uZWQgZm9yIGxvdHMgaW4gdGhvc2Ugc3VidXJicy4gVGhlIGBpbmR1c2AgdmFyaWFibGUgaXMgcmVhc29uYWJseSBoaWdoIHdpdGggMTglIHdoaWxlIHRoZSBtaW5pbXVtIGlzIDAlIGFuZCB0aGUgbWF4aW11bSBpcyAyNyUuIEJvdGggc3VidXJicyBhcmUgbm90IGNsb3NlIHRvIHRoZSBDaGFybGVzIFJpdmVyIGFuZCBoYXZlIGhpZ2ggbml0cm9nZW4gb3hpZGUgY29uY2VudHJhdGlvbiBhdCBhYm91dCA2OSUgd2l0aCB0aGUgbWF4aW11bSBiZWluZyA4NyUgYW5kIHRoZSBtaW5pbXVtIDM4JS4KClRoZWlyIG51bWJlciBvZiByb29tcyBwZXIgZHdlbGxpbmcgaXMgcHJldHR5IGF2ZXJhZ2UgYXQgNS40LzUuNiB3aGlsZSB0aGUgbWluIGlzIDMgYW5kIHRoZSBtYXggOS4gQm90aCBzdWJ1cmJzIGFyZSBjb21wbGV0ZWx5IG9jY3VwaWVkIGJ5IHVuaXRzIGJ1aWx0IHByaW9yIHRvIDE5NDAgYW5kIGFyZSByZWFzb25hYmx5IGNsb3NlIHRvIGZpdmUgQm9zdG9uIGVtcGxveW1lbnQgY2VudHJlcyAoMS40IHdoZW4gdGhlIG1pbmltdW0gaXMgMSBhbmQgdGhlIGhpZ2hlc3QgMTIuKSBBbHNvIGJvdGggYXJlIGF0IHRoZSBtYXhpbXVtIGluZGV4IG9mIGFjY2VzaWJpbGl0eSB0byByYWRpYWwgaGlnaHdheXMsIGFuZCB0aGF0J3MgcmVhc29uYWJseSBoaWdoIGFzIHRoZSBtaW5pbXVtIGlzIDEgYW5kIHRoZXkncmUgYXQgMjQuIAoKVGhlIHB1cGlsLXRlYWNoZXIgcmF0aW8gaXMgMjAuMiBhbmQgdGhlIG1pbmltdW0gaXMgMTIuIEFzIGV4cGVjdGVkLCBib3RoIHN1YnVyYnMgYXJlIGhpZ2hseSBwb3B1bGF0ZWQgYnkgYmxhY2tzLCB3aXRoIG9uZSBvZiB0aGUgc3VidXJicyBhY3R1YWxseSBiZWluZyB0aGUgbWF4aW11bSBudW1iZXIgaW4gdGhlIGRpc3RyaWJ1dGlvbi4gVGhlIGxvd2VyIHN0YXR1cyBvZiB0aGUgcG9wdWxhdGlvbiBpcyBub3QgdW51c3VhbGx5IGhpZ2gsIHdpdGggdGhlIG1heGltdW0gYW5kIG1pbmltdW0gYmVpbmcgMzcuOSBhbmQgMS43MyBhbmQgYm90aCBzdWJ1cmJzIGFyZSAzMC41IGFuZCAyMi45LgoKCihoKSBJbiB0aGlzIGRhdGEgc2V0LCBob3cgbWFueSBvZiB0aGUgc3VidXJicyBhdmVyYWdlIG1vcmUgdGhhbiBzZXZlbiByb29tcyBwZXIgZHdlbGxpbmc/IE1vcmUgdGhhbiBlaWdodCByb29tcyBwZXIgZHdlbGxpbmc/IENvbW1lbnQgb24gdGhlIHN1YnVyYnMgdGhhdCBhdmVyYWdlIG1vcmUgdGhhbiBlaWdodCByb29tcyBwZXIgZHdlbGxpbmcuCgpgYGB7cn0KdGFibGUoQm9zdG9uJHJtID4gNykKdGFibGUoQm9zdG9uJHJtID4gOCkKYGBgCk9ubHkgNjQgc3VidXJicyBhdmVyYWdlIGFib3ZlIHNldmVuIHJvb21zLCBhbmQgb25seSAxMyBhdmVyYWdlIGFib3ZlIGVpZ2h0IHJvb21zLgoKYGBge3J9CmhlYWQoQm9zdG9uW0Jvc3RvbiRybSA+IDgsIF0pCmBgYAoKVGhlcmUgYXJlIHNvbWUgb3V0bGllcnMgaW4gdGhlc2Ugc3VidXJicyBidXQgdGhleSBhbGwgaGF2ZSBoaWdoIGFnZSB2YWx1ZXMsIHNvIGEgbG90IG9mIG93bmVyIG9jY3VwaWVkIHVuaXRzIHByaW9yIHRvIDE5NDAuIEFsc28sIGFsbCBoYXZlIGhpZ2ggYmxhY2sgZGVuc2l0eSB3aXRoaW4gdGhlaXIgdG93bnMuIEFsbCBhcmUgZmFyIGZyb20gdGhlIENoYXJsZXMgUml2ZXIgZXhjZXB0IHN1YnVyYiAxNjQsIGFuZCB0aGUgcHJvcG9ydGlvbiBvZiByZXNpZGVudGlhbCBsYW5kIHpvbmUgZm9yIGxvdHMgb3ZlciAyNSwwMDAgc3EuZnQgaXMgemVybyB3aXRoIHRoZSBleGNlcHRpb24gb2Ygc3VidXJiIDIwNS4=